#!/usr/local/bin/tclsh
proc dec2bin_rev { dec bitCount } {
	set divident $dec
	set devider 2
	set quotient 0
	set result ""

	while { $divident >= $devider } {
		set result "$result[ expr $divident % $devider ]"
		set divident [ expr $divident / $devider ]
	}
	set result "$result$divident"
	while {[ string length $result ] < $bitCount } {
		set result "${result}0"
	}
	return $result
}

proc bin_rev2dec { bin_rev } {
	set dec 0
	for { set i 0 } { $i < [ string length $bin_rev ] } { incr i } {
		set dec [ expr $dec + ( 2**$i * [ string index $bin_rev $i ] ) ]
	}
	return $dec
}

proc inet_aton { address } {
	set netRegexp {^(([0-9]{1,3})\.){3}[0-9]{1,3}$}
	set checkResult [ regexp  $netRegexp $address matched ]
	if {!$checkResult} { return 0 }

	set octets [ split $matched '.' ]

	set reverseBinAddress ""

	for { set i 3 } { $i >= 0 } { incr i -1 } {
		set reverseBinAddress "$reverseBinAddress[ dec2bin_rev [ lindex $octets $i ] 8 ]"
	}

	return [ bin_rev2dec $reverseBinAddress ]
}

proc inet_ntoa { address } {
	set reverseBitAddress [ dec2bin_rev $address 32 ]
	set aResult ""
	for { set i 0 } { $i < 4 } { incr i } {
		set aResult "[ bin_rev2dec [ string range $reverseBitAddress [ expr $i*8 ] [ expr $i*8+7 ] ] ].${aResult}"
	}
	return [ string trim $aResult "." ]
}

proc inet_netAddress { ipAddress } {
	set ipRegexp {^(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9]{1,2})$}
	if {![ regexp $ipRegexp $ipAddress matched ip some prefix]} {
		puts error
		return false
	}
	set decIpAddress [ inet_aton $ip ]
	if { $decIpAddress == "0.0.0.0" } {
		return false
	}
	set bitCount [ expr 32 - $prefix ]
	set netAddress [ expr $decIpAddress >> $bitCount << $bitCount ]
	return [ inet_ntoa $netAddress ]
}

proc inet_hostCount { ipAddress } {
	set ipRegexp {^(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9]{1,2})$}
	if {![ regexp $ipRegexp $ipAddress matched ip some prefix]} {
		puts error
		return false
	}
	return [ expr round(pow(2, 32-$prefix)) ]
}

proc inet_firstHost { ipAddress } {
	set ipRegexp {^(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9]{1,2})$}
	if {![ regexp $ipRegexp $ipAddress matched ip some prefix]} {
		puts error
		return false
	}
	set decIpAddress [ inet_aton $ip ]
	if { $decIpAddress == "0.0.0.0" } {
		return false
	}
	set bitCount [ expr 32 - $prefix ]
	set netAddress [ expr ($decIpAddress >> $bitCount << $bitCount) + 1 ]
	return [ inet_ntoa $netAddress ]
}

# пример генерирования списка адресов:
# interp alias {} nextNetAddr {} _nextNetAddr "192.168.0.0"
# proc _nextNetAddr { hostAddress } {
#  set currentNetAddress [ inet_aton $hostAddress ]
#  set nextNetAddress [ expr $currentNetAddress + 1 ]
#  interp alias {} nextNetAddr {} _nextNetAddr [ inet_ntoa $nextNetAddress ]
#  return [ inet_ntoa $currentNetAddress ]
# }
#
# использование:
# set nextAddress [ nextNetAddr ]
# при каждом вызове nextNetAddr адрес будет увеличиваться на 1.
# При этом будут корректно обрабатываться увеличения соответствующих октетов.
# Для "переинициализации" функции нужно выполнить:
# interp alias {} nextNetAddr {} _nextNetAddr "192.168.0.0"
# в этом случае nextNetAddr будет возвращать адреса, начиная с указанного.

# пример реализации с возможностью задать максимальное кол-во адресов для генерирования.
# после генерирования указанного кол-ва адресов функция будет возвращать false
# interp alias {} nextNetAddr {} _nextNetAddr "192.168.0.0" 256
# proc _nextNetAddr { hostAddress {maxCount 0} { currentPos 0 } } {
#	if { $maxCount != 0 && $currentPos >= $maxCount } { return false }
#	set currentNetAddress [ inet_aton $hostAddress ]
#	set nextNetAddress [ expr $currentNetAddress + 1 ]
#	interp alias {} nextNetAddr {} _nextNetAddr [ inet_ntoa $nextNetAddress ] $maxCount [ incr currentPos ]
#	return [ inet_ntoa $currentNetAddress ]
# }
